#ifndef CONTROLOBJECT_H_
#define CONTROLOBJECT_H_

#include "Element.h"
#include "Control.h"

/**
 * \class ControlElement
 * \brief a class which stores Controls, the method of two-way communication in ProMDATE
 *
 * ControlElements are designed to represent actions which can be taken within programs.
 * For Example, performing a Monte Carlo experiment with a diverse set of parameter inputs.
 * This behavior is accomplished by defining ControlElements as container classes for more
 * specialized classes called Controls.  Controls are analogous to StatusElements but offer
 * two-way communication.
 *
 * ControlElements themselves offer several ways to communicate information  to the end-user.
 * They have descriptions which are set in the constructor as well as button names optionally
 * set in the constructor or by the method \a setButtonName().  This description and button
 * name will appear on the web page displayed by the server.
 *
 * All methods in ControlElement and it's derived classes are designed to be used internally.
 * If a module uses them, there is not provision to register these objects with ModuleHandler
 * and so the server cannot display them.
 */
class ControlElement: public Element {
public:
	/**
	 * \brief ControlElements must be constructed with a description and optionally with a button name.
	 * if no button name is specified the server will default to "Submit".
	 */
	ControlElement(std::string controlElementDescription, std::string nameOfDefaultButton = "");
	virtual ~ControlElement();

	/**
	 * \brief add a pre-defined Control to the ControlElement
	 * \param controlToAdd pointer to the new Control
	 * \return the ControlElement-context-unique identifier to the Control added
	 */
	int addControl(Control* controlToAdd);
	/**
	 * \brief remove a Control from the ControlElement
	 * \param identifier the ControlElement-context-unique identifier to a Control
	 * \return an error code 0 if success -1 if not
	 */
	int removeControl(int identifier);
	/**
	 * \brief rearange Controls within the ControlElement
	 * \param identifiers list of identifiers
	 * \param order list of the desired order
	 * \param lengthOfArrays length of the two arrays
	 *
	 * detailed description found in \a ModuleHandler::setControlOrderForControlElement()
	 */
	void setOrder(int* identifiers, int* order, int lengthOfArrays);

	int getNumberControls();
	/**
	 * \brief get the ControlElement-context-unique identifier for a Control based on the order which it appears
	 * \param positionInLineup the order number of the desired Control
	 * \param type a value to be changed to the value of enumerated type ordered at \a positionInLineup
	 */
	Control* getControlFromOrder(int positionInLineUp, int& type);
	/**
	 *\brief get a pointer to a Control based off it's identifier
	 *\param controlID the ControlElement-context-unique identifier of the desired Control
	 */
	Control* getControl(int controlID);
	/**
	 * \brief redefinition of \a Element::getType to return the correct value
	 * \return CONTROLELEMENT
	 */
	int getType();

	void setButtonName(std::string newButtonName);
	std::string getButtonName();

	/**
	 * \brief get a pointer to the ControlElement unique condition
	 * \return a pointer to the condition used to signal this ControlElement was pushed
	 */
	pthread_cond_t* getButtonCond();
	/**
	 * \brief get a pointer to the mutex for this ControlElement
	 * \return a pointer to the mutex specific to this ControlElement
	 */
	pthread_mutex_t* getButtonLock();

	void deleteLock();
	void deleteUnlock();

private:
	/**
	 * \brief the lock used to internally protect the ControlElement's list of Controls
	 */
	pthread_rwlock_t controlLock;
	/**
	 * \brief the number of Controls housed in the ControlElement
	 */
	int numControls;
	/**
	 * \brief double linked list to the Controls housed in the ControlElement
	 *
	 * The first index corresponds to the order in which the Controls were added
	 */
	Control** controlsList;
	/**
	 * \brief pointer array to the order of the Controls.
	 *
	 * The index of the array corresponds to the order in which the Control was added
	 */
	int** order;
	/**
	 * the string containing the button name for the ControlElement
	 */
	std::string buttonName;
	/**
	 * \brief the condition which signals \a ModuleHandler::buttonBroadcastListener()
	 *
	 * This is the ControlElement specific condition which is waited for by each
	 * \a ModuleHandler::buttonBroadcastListener().
	 */
	pthread_cond_t buttonCond;
	/**
	 * \brief the mutex which is used by \a ModuleHandler::buttonBroadcastListener()
	 *
	 * This is the ControlElement specific mutex used in \a ModuleHandler::buttonBroadcastListener()
	 */
	pthread_mutex_t buttonLock;
};

#endif /* CONTROLOBJECT_H_ */
